home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Language/OS - Multiplatform Resource Library
/
LANGUAGE OS.iso
/
gnu
/
ispell40.lha
/
ispell-4.0
/
screen.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-05-31
|
19KB
|
956 lines
/* Copyright (C) 1990, 1993 Free Software Foundation, Inc.
This file is part of GNU ISPELL.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stdio.h>
#include <ctype.h>
#include <setjmp.h>
#include <signal.h>
#include "ispell.h"
#include "hash.h"
int reading_interactive_command;
jmp_buf command_loop;
extern struct sp_corrections corrections;
#ifdef __STDC__
static void copyout (char **, int, FILE *);
#else
static void copyout ();
#endif
extern int lflag;
extern int uflag;
extern int iflag;
extern FILE *sortf;
extern int Sflag;
extern int intr_typed;
char tempfile[100];
#define NOPARITY 0x7f
static void
giveihelp ()
{
erase ();
printf ("You have interrupted ISPELL. Commands are:\r\n");
printf ("\r\n");
printf ("SPACE Continue scanning the current file.\r\n");
printf ("Q Write changes so far, and ignore misspellings in\r\n");
printf (" the rest of the file.\r\n");
printf ("X Abandon changes to this file.\r\n");
printf ("! Shell escape.\r\n");
printf ("^L Redraw screen.\r\n");
printf ("\r\n\r\n");
printf ("-- Type space to continue --");
fflush (stdout);
getchar ();
}
static void
givehelp ()
{
erase ();
(void) printf ("Whenever a word is found that is not in the dictionary,\r\n");
(void) printf ("it is printed on the first line of the screen. If the dictionary\r\n");
(void) printf ("contains any similar words, they are listed with a single digit\r\n");
(void) printf ("next to each one. You have the option of replacing the word\r\n");
(void) printf ("completely, or choosing one of the suggested words.\r\n");
(void) printf ("\r\n");
(void) printf ("Commands are:\r\n\r\n");
(void) printf ("R Replace the misspelled word completely.\r\n");
(void) printf ("Space Accept the word this time only\r\n");
(void) printf ("A Accept the word for the rest of this file.\r\n");
(void) printf ("I Accept the word, and put it in your private dictionary.\r\n");
(void) printf ("0-9 Replace with one of the suggested words.\r\n");
(void) printf ("<NL> Recompute near misses. Use this if you interrupted\r\n");
(void) printf (" the near miss generator, and you want it to\r\n");
(void) printf (" again on this word.\r\n");
(void) printf ("Q Write the rest of this file, ignoring misspellings,\r\n");
(void) printf (" and start next file.\r\n");
(void) printf ("X Exit immediately. Asks for conformation.\r\n");
(void) printf (" Leaves file unchanged.\r\n");
(void) printf ("! Shell escape.\r\n");
(void) printf ("^L Redraw screen.\r\n");
(void) printf ("\r\n\r\n");
(void) printf ("-- Type space to continue --");
(void) fflush (stdout);
(void) getchar ();
}
char *getline ();
char firstbuf[BUFSIZ], secondbuf[BUFSIZ];
char gtoken[BUFSIZ + 10];
int quit;
char *currentfile = NULL;
static long filesize;
static FILE *filestream;
int changed;
void
dofile (filename)
char *filename;
{
int c;
FILE *in, *out;
void (*oldf) (NOARGS);
currentfile = filename;
if ((in = fopen (filename, "r")) == NULL)
{
(void) fprintf (stderr, "Can't open %s\r\n", filename);
return;
}
changed = 0;
filesize = lseek (fileno (in), 0l, 2);
(void) lseek (fileno (in), 0l, 0);
if (access (filename, 2) < 0)
{
(void) fprintf (stderr, "Can't write to %s\r\n", filename);
return;
}
(void) strcpy (tempfile, "/usr/tmp/ispellXXXXXX");
(void) mktemp (tempfile);
if ((out = fopen (tempfile, "w")) == NULL)
{
(void) fprintf (stderr, "Can't create %s\r\n", tempfile);
return;
}
quit = 0;
checkfile (in, out, (long) 0);
(void) fclose (in);
(void) fclose (out);
if (changed == 0)
{
(void) unlink (tempfile);
tempfile[0] = 0;
return;
}
if ((in = fopen (tempfile, "r")) == NULL)
{
(void) fprintf (stderr, "tempoary file disappeared (%s)\r\n", tempfile);
(void) sleep (2);
return;
}
oldf = (void (*)(NOARGS)) signal (SIGINT, SIG_IGN);
if ((out = fopen (filename, "w")) == NULL)
{
(void) unlink (tempfile);
tempfile[0] = 0;
(void) fprintf (stderr, "can't create %s\r\n", filename);
(void) sleep (2);
return;
}
while ((c = getc (in)) != EOF)
putc (c, out);
fclose (in);
(void) fclose (out);
(void) unlink (tempfile);
tempfile[0] = 0;
signal (SIGINT, (RETSIGTYPE (*)()) oldf);
}
char *currentchar;
FILE *out;
void
checkfile (in, outx, end)
FILE *in, *outx;
long end;
{
char *p;
int maybe_troff;
char *cstart, *cend;
int i;
long lineoffset;
out = outx;
checkstart:
filestream = in;
secondbuf[0] = 0;
maybe_troff = 0;
while (1)
{
(void) strcpy (firstbuf, secondbuf);
if (quit)
{
if (out == NULL)
return;
while (fgets (secondbuf, sizeof secondbuf, in)
!= NULL)
(void) fputs (secondbuf, out);
break;
}
if (Sflag)
{
lineoffset = ftell (in);
if (end && lineoffset >= end)
break;
}
if (fgets (secondbuf, sizeof secondbuf, in) == NULL)
break;
/* uflag is on when emulating traditional spell
* if so, then follow troff commands '.so' and '.nx'
*/
if (uflag && !iflag && secondbuf[0] == '.')
{
int soflag = 0, nxflag = 0;
FILE *so;
char *n, *end;
if (strncmp (secondbuf, ".so", 3) == 0)
soflag = 1;
if (strncmp (secondbuf, ".nx", 3) == 0)
nxflag = 1;
if (soflag || nxflag)
{
n = secondbuf + 3;
while (isspace (*n))
n++;
end = n;
while (*end && !isspace (*end))
end++;
*end = 0;
if (strncmp (n, "/usr/lib", 8) == 0)
continue;
if (nxflag)
{
if (freopen (n, "r", in) == NULL)
{
(void) fprintf (stderr, "can't open %s\n",
n);
return;
}
goto checkstart;
}
if ((so = fopen (n, "r")) == NULL)
{
(void) fprintf (stderr,
"can't open %s\n", n);
}
else
{
/* FIXME: gcc -Wall found the third argument missing in this call
to checkfile. The function isn't documented, so I have no idea what
it actually is supposed flag. My assumption is that it worked in most
instances because random junk on the stack would likely be non-zero.
--bson */
checkfile (so, (FILE *) NULL, (long) 1);
(void) fclose (so);
}
continue;
}
}
currentchar = secondbuf;
p = secondbuf + strlen (secondbuf) - 1;
if (*p == '\n')
*p = 0;
while (1)
{
if (skip_to_next_word (out) == 0)
break;
cstart = currentchar;
cend = cstart;
if (intr_typed)
{
if (lflag || Sflag)
return;
gtoken[0] = 0;
(void) correct (gtoken, sizeof gtoken,
cstart, cend, ¤tchar);
if (quit)
{
(void) fputs (currentchar, out);
break;
}
intr_typed = 0;
}
/* first letter is a lexletter, therefore,
* loop will execute at least once
*/
p = gtoken;
i = 0;
while (islexletter (*cend) && i < MAX_WORD_LEN - 5)
{
*p++ = *cend++;
i++;
}
/* flush quote if at end of word */
if (p[-1] == '\'')
{
p--;
cend--;
}
*p = 0;
currentchar = cend;
if (good (gtoken, strlen (gtoken), 0))
{
if (out)
(void) fputs (gtoken, out);
continue;
}
interaction_flag = 1;
/* word is bad */
if (uflag)
{
/* traditional spell compatability */
(void) fputs (gtoken, sortf);
(void) putc ('\n', sortf);
/* don't report this word again by doing 'A' */
(void) p_enter (gtoken, 2, 0);
continue;
}
if (lflag)
{
/* make a simple list of bad words */
(void) puts (gtoken);
(void) p_enter (gtoken, 1, 0);
continue;
}
if (Sflag)
{
/* program interface */
(void) printf ("%ld\n", lineoffset + (cstart - secondbuf));
continue;
}
/* interactive mode */
if (correct (gtoken, sizeof gtoken,
cstart, cend, ¤tchar))
{
/* user accepted, or choose a near miss */
(void) fputs (gtoken, out);
if (quit)
{
(void) fputs (currentchar, out);
break;
}
}
else
{
/* user typed replacement, rescan */
currentchar = cstart;
}
}
if (out)
(void) putc ('\n', out);
}
}
/* return 0 if no more words on this line
* else return 1
*/
int
skip_to_next_word (out)
FILE *out;
{
switch (formatter)
{
case formatter_troff:
return (skip_to_next_word_troff ());
case formatter_tex:
return (skip_to_next_word_tex (out));
case formatter_generic:
default:
return (skip_to_next_word_generic ());
}
}
int
skip_to_next_word_generic ()
{
if (currentchar == secondbuf)
{
/* at beginning of line */
if (*currentchar == '.')
{
formatter = formatter_troff;
skip_to_next_word_troff ();
/* FIXME:
gcc -Wall found the argument missing. What is the return value supposed to
indicate? It used to just say "return;" --bson */
return 1;
}
}
while (*currentchar)
{
/* skip any leading apostrophes */
if (islexletter (*currentchar) && *currentchar != '\'')
return (1);
copyout (¤tchar, 1, out);
}
return (0);
}
int
skip_to_next_word_troff ()
{
if (currentchar == secondbuf)
{
/* at beginning of line */
/* if this is a formatter command, skip the line */
if (*currentchar == '.')
{
if (out)
{
while (*currentchar)
(void) putc (*currentchar++, out);
}
return (0);
}
}
while (*currentchar)
{
if (islexletter (*currentchar) && *currentchar != '\'')
return (1);
if (*currentchar != '\\')
{
copyout (¤tchar, 1, out);
continue;
}
if (currentchar[1] == 'f')
{
/* \fB or \f(XY */
if (currentchar[2] == '(')
copyout (¤tchar, 5, out);
else
copyout (¤tchar, 3, out);
}
else if (currentchar[1] == 's')
{
/* \s5 \s+2 \s-2 \s30
* skip one following character
* there may be more digits following, but
* they will get skipped since they are not
* lexletters
*/
copyout (¤tchar, 3, out);
}
else if (currentchar[1] == '(')
{
/* extended character set \(XY */
copyout (¤tchar, 3, out);
}
else if (currentchar[1] == '*')
{
/* string interpolation \*X \*(XY */
if (currentchar[2] == '(')
copyout (¤tchar, 5, out);
else
copyout (¤tchar, 3, out);
}
else
{
copyout (¤tchar, 1, out);
}
}
return (0);
}
/* return 1 if everyting ok, 0 to recheck some */
int
correct (token, toksiz, start, end, pcurrentchar)
char *token;
unsigned toksiz;
char *start, *end;
char **pcurrentchar;
{
int c;
int i;
char *p;
int len;
int needposs;
int intcnt = 0;
int mpinterrupted = 0;
/* zero length token just means to run the command loop */
len = strlen (token);
needposs = 1;
corrections.nwords = 0;
redraw:
(void) setjmp (command_loop);
erase ();
if (len)
{
(void) printf (" %s", token);
}
else
{
inverse ();
(void) printf ("(INTERRUPT)");
normal ();
needposs = 0;
}
if (currentfile)
(void) printf (" File: %s (%ld%%)", currentfile,
ftell (filestream) * 100 / filesize);
(void) printf ("\r\n\r\n");
if (needposs)
{
mpinterrupted = makepossibilities (token);
needposs = 0;
}
for (i = 0; i < corrections.nwords; i++)
{
if (corrections.posbuf[i][0] == 0)
break;
(void) printf ("%d: %s\r\n", i, corrections.posbuf[i]);
}
if (mpinterrupted)
(void) printf ("(near miss generator interrupted; type return to rerun)\r\n");
move (15, 0);
(void) printf ("%s\r\n", firstbuf);
for (p = secondbuf; p != start; p++)
(void) putchar (*p);
inverse ();
for (i = len; i > 0; i--)
(void) putchar (*p++);
normal ();
while (*p)
(void) putchar (*p++);
(void) printf ("\r\n");
while (1)
{
(void) fflush (stdout);
intr_typed = 0;
reading_interactive_command = 1;
c = getchar ();
reading_interactive_command = 0;
if (c == -1)
{
intcnt++;
if (intcnt == 10)
{
quit = 1;
erase ();
return (1);
}
goto redraw;
}
intcnt = 0;
c &= NOPARITY;
switch (c)
{
case '\r':
case '\n':
if (len)
needposs = 1;
goto redraw;
case 'Z' & 037:
case 'Y' & 037:
case 'Z':
stop ();
goto redraw;
case ' ': /* accept this time only */
erase ();
return 1;
case 'x':
case 'X': /* exit without writing */
(void) printf ("Exit without writing changes? ");
(void) fflush (stdout);
c = (getchar () & NOPARITY);
if (c == 'y' || c == 'Y')
{
erase ();
done ();
}
termbeep ();
goto redraw;
case 'i':
case 'I': /* put in private dictionary */
if (len == 0)
break;
if (len < MAX_WORD_LEN - 5)
(void) p_enter (token, 1, 1);
erase ();
return 1;
case 'a':
case 'A': /* don't report again this session */
if (len == 0)
break;
if (len < MAX_WORD_LEN - 5)
(void) p_enter (token, 1, 0);
erase ();
return 1;
case 'L' & 037: /* redraw */
goto redraw;
case '?': /* help */
if (len == 0)
giveihelp ();
else
givehelp ();
goto redraw;
case '!':
{
char buf[200];
move (18, 0);
(void) putchar ('!');
if (getline (buf, sizeof buf) == NULL)
goto redraw;
(void) printf ("\r\n");
shellescape (buf);
goto redraw;
}
case 'r':
case 'R':
if (len == 0)
break;
move (18, 0);
(void) printf ("Replace with: ");
if (getline (token, toksiz) == NULL)
goto redraw;
inserttoken (secondbuf, start, end, token, (char **) NULL);
erase ();
return 0; /* 0 means rescan */
case 'l':
case 'L':
move (18, 0);
(void) printf ("Lookup (regular expression): ");
if (getline (token, toksiz) == NULL)
goto redraw;
move (19, 0);
termflush ();
dolook_interactive (token);
goto redraw;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
if (corrections.posbuf[c - '0'][0] != 0)
{
(void) strcpy (token, corrections.posbuf[c - '0']);
inserttoken (secondbuf, start, end, token,
pcurrentchar);
erase ();
return 1;
}
break;
case 'q':
case 'Q':
quit = 1;
erase ();
return 1;
default:
break;
}
termbeep ();
}
}
/*
* buf is line
* replace between start and end with token
*/
void
inserttoken (buf, start, end, token, pcurrentchar)
char *buf, *start, *end, *token;
char **pcurrentchar;
{
char copy[BUFSIZ];
char *p, *q;
changed = 1;
/* copy up to start */
for (p = copy, q = buf; q != start; p++, q++)
*p = *q;
/* put in token */
while (*token)
*p++ = *token++;
/* remember place in buf */
if (pcurrentchar)
*pcurrentchar = buf + (p - copy);
/* skip over old stuff */
q = end;
/* copy the tail of the line */
while (*q)
*p++ = *q++;
*p = 0;
(void) strcpy (buf, copy);
}
char *
getline (s, siz)
char *s;
unsigned siz;
{
char *p;
int c;
extern int erasechar, killchar;
int pos;
if (siz <= 1)
return (NULL);
siz--;
p = s;
pos = 0;
while (1)
{
c = (getchar () & NOPARITY);
if (c == '\\')
{
if (pos == siz)
{
p--;
pos--;
backup ();
}
(void) putchar ('\\');
c = (getchar () & NOPARITY);
backup ();
(void) putchar (c);
*p++ = c;
pos++;
}
else if (c == ('G' & 037))
{
return (NULL);
}
else if (c == '\n' || c == '\r')
{
*p = 0;
return (s);
}
else if (c == erasechar)
{
if (p != s)
{
p--;
backup ();
(void) putchar (' ');
backup ();
}
}
else if (c == killchar)
{
while (p != s)
{
p--;
backup ();
(void) putchar (' ');
backup ();
}
}
else
{
if (pos == siz)
{
p--;
pos--;
backup ();
}
*p++ = c;
(void) putchar (c);
}
}
}
void
askmode (verbose)
int verbose;
{
char buf[MAX_WORD_LEN];
int i;
int len;
setbuf (stdin, (char *) NULL);
setbuf (stdout, (char *) NULL);
while (1)
{
if (verbose)
{
(void) printf ("word: ");
(void) fflush (stdout);
}
if (fgets (buf, MAX_WORD_LEN - 5, stdin) == NULL)
break;
len = strlen (buf);
if (len && buf[len - 1] == '\n')
buf[--len] = 0;
if (verbose && len == 0)
continue;
if (good (buf, strlen (buf), 0))
{
/* used to print + if rootword */
if (verbose)
(void) printf ("ok\n");
else
(void) printf ("*\n");
}
else
{
(void) makepossibilities (buf);
if (corrections.posbuf[0][0])
{
if (verbose)
(void) printf ("how about: ");
else
(void) printf ("& ");
for (i = 0; i < 10; i++)
{
if (corrections.posbuf[i][0] == 0)
break;
(void) printf ("%s ",
corrections.posbuf[i]);
}
(void) printf ("\n");
}
else
{
if (verbose)
(void) printf ("not found\n");
else
(void) printf ("#\n");
}
}
}
}
static void
copyout (cc, cnt, out)
char **cc;
int cnt;
FILE *out;
{
while (--cnt >= 0)
{
if (*(*cc) == 0)
break;
if (out)
(void) putc (*(*cc), out);
(*cc)++;
}
}
static char *lookcmd, *lookarg1, *lookarg2;
/* this runs in a child with the terminal set back to normal
* and with the parent ignoring signals
*/
void
lookfun (NOARGS)
{
if (lookarg2 == NULL)
(void) execlp (lookcmd, lookcmd, lookarg1, NULL);
else
(void) execlp (lookcmd, lookcmd, lookarg1, lookarg2, NULL);
}
void
dolook (str)
char *str;
{
char *p;
int wild = 0;
for (p = str; *p; p++)
{
if (strchr (".*[\\", *p) != NULL)
wild = 1;
if (isupper (*p))
*p = tolower (*p);
}
if (wild == 0)
{
lookcmd = "look";
lookarg1 = str;
lookarg2 = NULL;
if (!dochild (lookfun))
return;
}
lookcmd = "egrep";
lookarg1 = str;
lookarg2 = "/usr/lib/ispell.words";
dochild (lookfun);
}
void
dolook_interactive (str)
char *str;
{
dolook (str);
(void) printf ("\n-- Type space to continue --");
(void) getchar ();
}